package com.xuelang.pipeline.app.pipeline.impl;

import com.xuelang.hiforce.base.tracing.TracingUtils;
import com.xuelang.pipeline.app.pipeline.PipelineSchedulerService;
import com.xuelang.pipeline.app.pipeline.job.PipelineJob;
import com.xuelang.pipeline.client.common.exception.BizException;
import com.xuelang.pipeline.client.pipeline.enums.TriggerWayEnum;
import com.xuelang.pipeline.domain.pipeline.Pipeline;
import com.xuelang.pipeline.domain.pipeline.TriggerSetting;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Objects;

/**
 * <p>流水线定时任务服务接口实现类</p>
 *
 * @author : yixin.lys
 * @date : 2024-06-11 18:18
 **/
@Slf4j
@Service
public class PipelineSchedulerServiceImpl implements PipelineSchedulerService {

    @Autowired
    private Scheduler scheduler;

    @Override
    public void addJob(Pipeline pipeline, TriggerSetting triggerSetting) throws SchedulerException {
        String code = pipeline.getCode();
        String group = pipeline.getGroups();
        String cronExpression = triggerSetting.getCronExpression();
        String triggerTimeStr = triggerSetting.getTriggerTime();
        Integer triggerWay = triggerSetting.getTriggerWay();
        Date triggerTime = parseDate(triggerTimeStr, "yyyy-MM-dd HH:mm:ss");
        if (StringUtils.isBlank(group)) {
            group = Scheduler.DEFAULT_GROUP;
        }
        JobKey jobKey = new JobKey(code, group);
        JobDataMap jobDataMap = new JobDataMap();
        jobDataMap.put("pipelineCode", code);
        jobDataMap.put("triggerWay", triggerWay);
        jobDataMap.put("userId", TracingUtils.getUserId());

        if (scheduler.checkExists(jobKey)) {
            throw new SchedulerException("Job already exists: " + code);
        }

        JobDetail jobDetail = JobBuilder.newJob(PipelineJob.class)
                .withIdentity(jobKey)
                .usingJobData(jobDataMap)
                .build();

        Trigger trigger;
        if (triggerWay.equals(TriggerWayEnum.PERIOD.getValue()) && StringUtils.isNotBlank(cronExpression)) {
            if (StringUtils.isBlank(cronExpression)) {
                throw new BizException("周期触发配置不可为空！");
            }
            trigger = TriggerBuilder.newTrigger()
                    .withIdentity("trigger_" + code, group)
                    .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)
                            .withMisfireHandlingInstructionFireAndProceed())
                    .build();
        } else {
            if (Objects.isNull(triggerTime)) {
                throw new BizException("触发时间不可为空！");
            }
            trigger = TriggerBuilder.newTrigger()
                    .withIdentity("trigger_" + code, group)
                    .startAt(triggerTime)
                    .build();
        }

        scheduler.scheduleJob(jobDetail, trigger);
        log.debug("Scheduled new job: " + code + " with start time: " + triggerTime + " and cron expression: " + cronExpression);
    }

    @Override
    public void updateJob(Pipeline pipeline, TriggerSetting triggerSetting) throws SchedulerException {
        String code = pipeline.getCode();
        String group = pipeline.getGroups();
        String cronExpression = triggerSetting.getCronExpression();
        String triggerTimeStr = triggerSetting.getTriggerTime();
        Integer triggerWay = triggerSetting.getTriggerWay();
        Date triggerTime = parseDate(triggerTimeStr, "yyyy-MM-dd HH:mm:ss");
        if (StringUtils.isBlank(group)) {
            group = Scheduler.DEFAULT_GROUP;
        }
        JobKey jobKey = new JobKey(code, group);
        TriggerKey triggerKey = new TriggerKey("trigger_" + code, group);

        // 删除旧的触发器
        if (scheduler.checkExists(triggerKey)) {
            scheduler.unscheduleJob(triggerKey);
            log.debug("Removed old trigger: " + triggerKey);
        }

        // 删除旧的任务
        if (scheduler.checkExists(jobKey)) {
            scheduler.deleteJob(jobKey);
            log.debug("Removed old job: " + jobKey);
        }

        JobDataMap jobDataMap = new JobDataMap();
        jobDataMap.put("pipelineCode", code);
        jobDataMap.put("triggerWay", triggerWay);
        jobDataMap.put("userId", TracingUtils.getUserId());

        // 创建新的任务
        JobDetail jobDetail = JobBuilder.newJob(PipelineJob.class)
                .withIdentity(jobKey)
                .usingJobData(jobDataMap)
                .build();

        // 创建新的触发器
        Trigger trigger;
        if (triggerWay.equals(TriggerWayEnum.PERIOD.getValue()) && StringUtils.isNotBlank(cronExpression)) {
            trigger = TriggerBuilder.newTrigger()
                    .withIdentity(triggerKey)
                    .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)
                            .withMisfireHandlingInstructionFireAndProceed()) // 配置misfire策略
                    .build();
        } else {
            trigger = TriggerBuilder.newTrigger()
                    .withIdentity(triggerKey)
                    .startAt(triggerTime)
                    .build();
        }

        // 重新调度任务
        scheduler.scheduleJob(jobDetail, trigger);
        log.info("Scheduled new job: " + code + " with start time: " + triggerTime + " and cron expression: " + cronExpression);
    }

    @Override
    public void removeJob(Pipeline pipeline) throws SchedulerException {
        String code = pipeline.getCode();
        String group = pipeline.getGroups();
        if (StringUtils.isBlank(group)) {
            group = Scheduler.DEFAULT_GROUP;
        }
        JobKey jobKey = new JobKey(code, group);
        TriggerKey triggerKey = new TriggerKey("trigger_" + code, group);

        // 删除触发器
        if (scheduler.checkExists(triggerKey)) {
            scheduler.unscheduleJob(triggerKey);
            log.debug("Removed trigger: " + triggerKey);
        }

        // 删除任务
        if (scheduler.checkExists(jobKey)) {
            scheduler.deleteJob(jobKey);
            log.debug("Removed job: " + jobKey);
        }
        log.debug("Removed job: " + code);
    }

    private Date parseDate(String dateString, String dateFormat) {
        SimpleDateFormat formatter = new SimpleDateFormat(dateFormat);
        if (StringUtils.isBlank(dateString)) {
            return null;
        }
        try {
            // 解析日期字符串
            return formatter.parse(dateString);
        } catch (ParseException e) {
            // 捕获解析异常并打印错误信息
            System.out.println("解析日期字符串时出错: " + e.getMessage());
            return null;
        }
    }
}
